前向投影的解析计算
要求
编写实现扇形束或平行束CT前向投影解析计算的代码,获取Shepp Logan
仿体的前向投影, 并显示对应的sinogram
图;将Shepp Logan
修改为一个非常小的点源
,采用前向投影解析计算的代码,计算该点源的Sinogram
图并显示。
注意:Shepp Logan仿体定义有很多变体,实现是选取其中一个即可。
思路
前向投影的解析计算方法,计算对应图像的每一个点投影到探测器对应位置,统计每个角度每个探测器上的数值。
可以通过两步进行计算:
(1)根据探测器角度与探测器编号计算对应探测器的直线方程,该直线从探测器上一点到图像;
(2)计算该直线方程穿过的椭圆长度,并结合椭圆强度值,计算穿过的所有椭圆长度乘强度之和作为该探测器的接收值;
通过两个函数分别实现:
CalSlope()
:对直线方程的计算;
CalDis3()
:统计探测器接收的信号;
Sheep Logan仿体
使用椭圆函数定义的方法构建Sheep-Logan图像
% 强度 半长轴 半短轴 位置x 位置y 倾斜度
ellipse = [ 1 .69 .92 0 0 0
-.8 .6624 .8740 0 -.0184 0
-.2 .1100 .3100 .22 0 -18
-.2 .1600 .4100 -.22 0 18
.1 .2100 .2500 0 .35 0
.1 .0460 .0460 0 .1 0
.1 .0460 .0460 0 -.1 0
.1 .0460 .0230 -.08 -.605 0
.1 .0230 .0230 0 -.606 0
.1 .0230 .0460 .06 -.605 0 ];
I = phantom(ellipse,256);
figure
imshow(I,[])
由投影结果可以看出,解析法在θ
为0度和180度时出现比较明显的错误,原因是函数定义直线y = k*x + b
。在探测器旋转过程中,当k = ∞
时,直线函数变为x = a
。
点源仿体
使用较小的圆
%点源参数(一个较小的圆)
point = [ 1 .01 .01 0 0.3 0 ];
I = phantom(point,256);
figure
imshow(I,[])
由投影结果可以看到,对于单个点源图像的计算由比较大的误差,其中部分角度缺失,投影质量较差。
代码
主程序
clc,clear
%shepp-logan模型的参数
% 强度 半长轴 半短轴 位置x 位置y 倾斜度
ellipse = [ 1 .69 .92 0 0 0
-.8 .6624 .8740 0 -.0184 0
-.2 .1100 .3100 .22 0 -18
-.2 .1600 .4100 -.22 0 18
.1 .2100 .2500 0 .35 0
.1 .0460 .0460 0 .1 0
.1 .0460 .0460 0 -.1 0
.1 .0460 .0230 -.08 -.605 0
.1 .0230 .0230 0 -.606 0
.1 .0230 .0460 .06 -.605 0 ];
%点源参数(一个较小的圆)
point = [ 1 .05 .05 0 0.3 0 ];
% 参数设定
NumDetector = 128; % 探测器数量
NumAngle = 360; % 旋转角度
ImgSize = [128,128]; % 设定图像大小
P = point;
I = phantom(P,256);
figure
imshow(I,[])
Rdata = zeros(NumDetector,NumAngle);
for i = 1:NumAngle
for j = 1:NumDetector
[k,b] = CalSlope(ImgSize,i,j,NumDetector);
tmp = 0;
for z = 1:size(P,1)
tmp = tmp + CalDis3(k,b,P(z,:),ImgSize(1));
end
Rdata(j,i) = tmp;
end
end
figure
imshow(Rdata,[0,40])
colorbar()
colormap(gray)
title("Shepp-Logan解析法投影图")
%title("Point解析法投影图")
函数
function [k,b] = CalSlope(ImgSize, angle, num, NumDetector)
% 本函数用于计算探测器在特定偏转角度,穿过特定探测晶体中心的直线方程
% Imgsize 图像大小
% angle 偏转角度
% num 晶体排序
% NumberDetector 晶体总数
DisAbord = 100;
%角度弧度制转换
anglePi = pi*angle / 180;
%计算k
%k1 = tan(anglePi);
if angle == 0
k = 1;
elseif angle == 90
k = 0;
else
k = -1/tan(anglePi);
end
%计算最中心的传感器的坐标
center_x = ImgSize(2)/2+sin(anglePi)*DisAbord;
center_y = ImgSize(1)/2-cos(anglePi)*DisAbord;
%算出第num个传感器距离中心的距离
DisCenter = (num-(NumDetector+1)/2);
%计算第num个传感器的坐标
x = center_x + DisCenter*cos(anglePi);
y = center_y + DisCenter*sin(anglePi);
%根据y=kx+b计算b
b = y - k*x;
end
function value = CalDis3(k_,b_,ellipse,width)
% 本函数用于计算直线穿过椭圆的长度
% k_ 直线斜率
% b_ 直线常量
% ellipse 以函数形式定义的椭圆
% width 图像宽度
% 椭圆参数
A = ellipse(1);
a = ellipse(2);
b = ellipse(3);
x0 = ellipse(4);
y0 = ellipse(5);
anglePi = pi*ellipse(6) / 180;
% 坐标系转换 (0,0)->(width/2,width/2)
b_= k_-1 + b_*2/width;
%将直线方程带入到旋转的椭圆方程中
% t2、t1、t0分别代表带入后的x的二次、一次以及常数项
k1 = cos(anglePi)+k_*sin(anglePi);
b1 = (b_-y0)*sin(anglePi)-x0*cos(anglePi);
k2 = k_*cos(anglePi)-sin(anglePi);
b2 = x0*sin(anglePi)+(b_-y0)*cos(anglePi);
t2 = b^2*k1^2+a^2*k2^2;
t1 = 2*b^2*k1*b1+2*a^2*k2*b2;
t0 = b^2*b1^2+a^2*b2^2-a^2*b^2;
delta = t1^2-4*t2*t0;
if delta<=0
value = 0;
else
x1 = (-t1-delta^0.5)/(2*t2);
x2 = (-t1+delta^0.5)/(2*t2);
y1 = k_*x1+b_;
y2 = k_*x2+b_;
value = ((x1-x2)^2+(y1-y2)^2)^0.5;
end
value = value*width/2*A;
end